﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using System.Text.RegularExpressions;
using Image = System.Drawing.Image;

namespace SuperKit
{
    public delegate void GeneralOutput(string format, params object[] args);

    public class Kit
    {
        public const int NONE = -1;
        public const string EMPTY = "";
        public const char ELEMENT_SPLIT = ',';
        public const char CATALOG_SPLIT = '|';
        public const string ALL_EXT = ".*";
        public const string ALL_EXT2 = "*.*";
        public const string FAVOR_START = "(★)";
        public const string FAVOR_START_S = "★";
        public static readonly string[] EMPTY_LIST = new string[] { };
        public const int KB = 1024;
        public const int MB = KB * KB;
        public const int GB = MB * KB;

        public static readonly string[] ALL_EXTS = new string[] { ALL_EXT };
        public static readonly string[] IMG_EXTS = new string[] { ".jpg", ".png", ".bmp", ".gif", ".jpeg", ".webp" };
        public static readonly string[] EFFECT_IMG_EXTS = new string[] { ".jpg", ".png", ".bmp", ".jpeg" };
        public static readonly string[] PROCESSED_IMG_EXTS = new string[] { ".jpg", ".png", ".bmp" };
        public static readonly string[] ZIP_EXTS = new string[] { ".zip", ".rar", ".7z", ".tar" };
        public static readonly string[] PAK_EXTS = new string[] { ".pak" };
        public static readonly string[] PDF_EXTS = new string[] { ".pdf" };
        public static readonly string[] MEDIA_EXT = new string[] { ".mp4", ".mkv", ".mp3", ".avi", ".wav", ".mpg", ".mov" };

        public const float TINY = 0.0000001f;
        public static readonly DateTime CenturyBegin = new DateTime(2001, 1, 1);

        public const string IC_DUMMY = "ic_dummy.png";
        public const string IC_FOLDER = "ic_folder.png";
        public const string IC_FILE = "ic_file.png";
        public const string IC_IMAGE = "ic_pic.png";
        public const string IC_ZIP = "ic_zip.png";
        public const string IC_VIDEO = "ic_video.png";
        public static readonly string[] IC_LIST = new string[] { IC_FOLDER, IC_FILE, IC_IMAGE, IC_ZIP, IC_VIDEO };
        public static string AppPath => AppDomain.CurrentDomain.BaseDirectory;

        public static bool IsEmpty<T>(T[] list)
        {
            return list == null || list.Length == 0;
        }

        static public bool IsEqual(string a, string b)
        {
            return string.Equals(a, b, StringComparison.OrdinalIgnoreCase);
        }

        public static bool IsEmpty(string str)
        {
            return str == null || str.Length == 0;
        }

        public static bool IsZero(float value)
        {
            return value * value < TINY;
        }
        public static void Swap(ref int a, ref int b)
        {
            int tmp = b;
            b = a;
            a = tmp;
        }

        public static double SecondsTick
        {
            get
            {
                DateTime currentDate = DateTime.Now;
                long elapsedTicks = currentDate.Ticks - CenturyBegin.Ticks;
                TimeSpan elapsedSpan = new TimeSpan(elapsedTicks);
                return elapsedSpan.TotalSeconds;
            }
        }


        public static bool IsFileType(FileInfo info, params string[] types)
        {
            // 不指定类型，则任何文件都通过
            if (types == null) {
                return true;
            }

            foreach (string i in types)
            {
                if (ALL_EXT == i || ALL_EXT2 == i)
                { // 通配符
                    return true;
                }
                if (i.Equals(info.Extension, StringComparison.OrdinalIgnoreCase))
                {
                    return true;
                }
            }
            return false;
        }

        public static string GetImagePath(string name)
        {
            return Path.Combine(AppPath, "Images", name);
        }

        public static string AutoShorten(string name, int limit)
        {
            if (limit == 0)
            {
                return name;
            }
            if (name.Length < limit)
            {
                return name;
            }
            return name.Substring(0, limit);
        }

        public static bool IsComment(string str)
        {
            if (IsEmpty(str)) return true;
            return str.Trim().IndexOf('#') == 0;
        }

        /// <summary>此方法检查此文件是否存在，如果已经存在，则在文件后面加“_标号”</summary>
        public static string GetNonExistName(string path)
        {
            if (!File.Exists(path))
            {
                return path;
            }

            var ext = Path.GetExtension(path);
            var pureName = Path.GetFileNameWithoutExtension(path);
            var dir = Path.GetDirectoryName(path);


            for (int i = 0; i < 1000; i++)
            {
                var newName = string.Format("{0}_{1}{2}", pureName, i + 1, ext);
                var newPath = Path.Combine(dir, newName);
                if (!File.Exists(newPath))
                {
                    return newPath;
                }
            }

            return string.Empty;
        }

        public static string GetNonExistDirName(string path)
        {
            if (!Directory.Exists(path))
            {
                return path;
            }

            var pureName = Path.GetFileName(path);
            var dir = Path.GetDirectoryName(path);


            for (int i = 0; i < 1000; i++)
            {
                var newName = string.Format("{0}_{1}", pureName, i + 1);
                var newPath = Path.Combine(dir, newName);
                if (!Directory.Exists(newPath))
                {
                    return newPath;
                }
            }

            return string.Empty;
        }

        public static ImageCodecInfo GetEncoder(ImageFormat format)
        {
            ImageCodecInfo[] codecs = ImageCodecInfo.GetImageDecoders();
            foreach (ImageCodecInfo codec in codecs)
            {
                if (codec.FormatID == format.Guid)
                {
                    return codec;
                }
            }
            return null;
        }

        public static Size GetResize(Image bitmap, int maxWidth, int maxHeight)
        {
            Size s = new Size(0, 0);
            if (!(bitmap.Width > maxWidth || bitmap.Height > maxHeight))
            {
                s.Width = bitmap.Width;
                s.Height = bitmap.Height;
                return s;
            }


            var rate = (float)bitmap.Width / bitmap.Height;
            if (bitmap.Width > bitmap.Height)
            {
                s.Width = maxWidth;
                s.Height = (int)(maxWidth / rate);
            }
            else
            {
                s.Width = (int)(maxHeight * rate);
                s.Height = maxHeight;
            }

            return s;
        }

        public static string ReplaceRegex(string s, string reg, string replace = EMPTY)
        {
            Regex r = new Regex(reg);
            string newName = s;
            if (r.IsMatch(s))
            {
                newName = r.Replace(s, EMPTY);
            }
            return newName;
        }

        /// <summary>
        /// 获取一个路径下面的全部目录，包括自身。
        /// </summary>
        /// <param name="list">需要将目录填充的列表。如果为空，会创建一个列表</param>
        /// <param name="dir">需要执行扫描的目录</param>
        /// <returns>做为参数传入的列表，如果传入为空，返回新建的列表。</returns>
        public static List<DirectoryInfo> GetAllDirectories(List<DirectoryInfo> list, DirectoryInfo dir)
        {
            if (list == null)
            {
                list = new List<DirectoryInfo>();
            }

            // 先加入自身
            list.Add(dir);

            // 检查每一个子目录
            var dirs = dir.GetDirectories();
            if (dirs == null || dirs.Length == 0)
            {
                return list;
            }

            foreach (var i in dirs)
            {
                GetAllDirectories(list, i);
            }

            return list;
        }

        /// <summary>
        /// 获取一个路径下面的全部文件。
        /// </summary>
        /// <param name="list">需要将目录填充的列表。如果为空，会创建一个列表</param>
        /// <param name="dir">需要执行扫描的目录</param>
        /// <returns>做为参数传入的列表，如果传入为空，返回新建的列表。</returns>
        public static List<FileInfo> GetAllFiles(List<FileInfo> list, DirectoryInfo dir)
        {
            return GetAllFiles(list, dir, null);
        }

        /// <summary>
        /// 获取一个路径下面的全部文件。指定文件类型。
        /// </summary>
        /// <param name="list">需要将目录填充的列表。如果为空，会创建一个列表</param>
        /// <param name="dir">需要执行扫描的目录</param>
        /// <param name="exts">需要检查的文件扩展名类型，格式为“.mp4”（需要加“.”号），如果为空，则返回所有类型的文件</param>
        /// <returns>做为参数传入的列表，如果传入为空，返回新建的列表。</returns>
        public static List<FileInfo> GetAllFiles(List<FileInfo> list, DirectoryInfo dir, string[] exts)
        {
            if (list == null)
            {
                list = new List<FileInfo>();
            }

            // 检查每一个子目录
            var files = dir.GetFiles();
            if (files != null && files.Length > 0)
            {
                foreach (var i in files)
                {
                    if (exts != null && IsFileType(i, exts) == false)
                    {
                        continue;
                    }
                    list.Add(i);
                }
            }

            var dirs = dir.GetDirectories();
            if (dirs != null && dirs.Length > 0)
            {
                foreach (var i in dirs)
                {
                    GetAllFiles(list, i, exts);
                }
            }

            return list;
        }

        public static int CountAllFiles(DirectoryInfo dir, string[] exts)
        {
            int count = 0;

            // 检查每一个子目录
            var files = dir.GetFiles();
            if (files != null && files.Length > 0)
            {
                foreach (var i in files)
                {
                    if (exts != null && IsFileType(i, exts) == false)
                    {
                        continue;
                    }
                    count++;
                }
            }

            var dirs = dir.GetDirectories();
            if (dirs != null && dirs.Length > 0)
            {
                foreach (var i in dirs)
                {
                    count += CountAllFiles(i, exts);
                }
            }

            return count;
        }

        public static List<FileInfo> GetFilteredFiles(List<FileInfo> list, string[] exts)
        {
            var flist = new List<FileInfo>();
            foreach (var i in list)
            {
                if (IsFileType(i, exts))
                {
                    flist.Add(i);
                }
            }
            return flist;
        }



        /// <summary>
        /// 如果此文件的目录不存在，则创建一个。
        /// </summary>
        /// <param name="file">文件名</param>
        public static void CheckFileDirectory(FileInfo file)
        {
            if (file.Directory.Exists == false)
            {
                file.Directory.Create();
            }
        }

        /// <summary>
        /// 获取当前时间到一个时间戳的时间经过。
        /// </summary>
        /// <param name="date">记录的时间戳</param>
        /// <returns>返回一个XXmXXs这样的多少分，多少秒的格式。</returns>
        public static string GetPassTime(DateTime date)
        {
            var second = (int)(DateTime.Now - date).TotalSeconds;
            var minute = second / 60;
            if (minute < 60)
            {
                return string.Format("{0}m{1}s", minute, second % 60);
            }
            else
            {
                var hour = minute / 60;
                return string.Format("{0}h{1}m{2}s", hour, minute % 60, second % 60);
            }

        }

        /// <summary>
        /// 将文件的扩展名替换。
        /// </summary>
        /// <param name="path">要替换的文件完整路径。</param>
        /// <param name="ext">要替换的扩展名，注意需要使用“.mp4”，包括“.”号。</param>
        /// <returns>修改后的文件完整路径</returns>
        public static string ChangeExtension(string path, string ext)
        {
            FileInfo info = new FileInfo(path);
            return Path.Combine(info.DirectoryName, $"{Path.GetFileNameWithoutExtension(info.Name)}{ext}");
        }

        public static int Len<T>(T[] arr)
        {
            return arr == null ? 0 : arr.Length;
        }
        public static int Len<T>(List<T> arr)
        {
            return arr == null ? 0 : arr.Count;
        }

        public static void Beep()
        {
            System.Media.SystemSounds.Hand.Play();
        }

        public static string AddFavorStar(string txt, string mark = FAVOR_START)
        {
            txt = txt.Replace(mark, "");
            txt = txt.Replace("★", "");
            return mark + txt;
        }
        public static string ToggleFavorStar(string txt, string mark = FAVOR_START)
        {
            if (txt.IndexOf(mark) != -1)
            {
                txt = txt.Replace(mark, "");
                txt = txt.Replace("★", "");
            }
            else
            {
                txt = mark + txt;
            }
            return txt;
        }

        public static Size TextToSize(string text)
        {
            if (IsEmpty(text))
            {
                return new Size(0, 0);
            }
            int index = text.IndexOf("x", StringComparison.OrdinalIgnoreCase);

            // 当只有一个值的时候，宽高都是此项
            if (index == -1)
            {
                int size = int.Parse(text);
                return new Size(size, size);
            }

            int width = int.Parse(text.Substring(0, index));
            int height = int.Parse(text.Substring(index + 1));

            return new Size(width, height);
        }

        public static Bitmap ResizeImage(Image bmp, int newWidth, int newHeight, InterpolationMode mode = InterpolationMode.Default)
        {
            Bitmap b = new Bitmap(newWidth, newHeight);
            Graphics g = Graphics.FromImage(b);
            g.InterpolationMode = mode;
            if (bmp != null)
            {
                g.DrawImage(bmp, new Rectangle(0, 0, newWidth, newHeight),
                    new Rectangle(0, 0, bmp.Width, bmp.Height), GraphicsUnit.Pixel);
            }
            g.Dispose();
            return b;
        }


        public static Bitmap CopyImage(Image bmp)
        {
            Bitmap b = new Bitmap(bmp.Width, bmp.Height);
            Graphics g = Graphics.FromImage(b);
            g.InterpolationMode = InterpolationMode.HighQualityBicubic;
            g.DrawImage(bmp, new Rectangle(0, 0, bmp.Width, bmp.Height),
                new Rectangle(0, 0, bmp.Width, bmp.Height), GraphicsUnit.Pixel);
            g.Dispose();
            return b;
        }

        public static bool IsInArea(Point point, Rectangle selectRect)
        {
            if (point.X < selectRect.X) return false;
            if (point.Y < selectRect.Y) return false;
            if (point.X > selectRect.X + selectRect.Width) return false;
            if (point.Y > selectRect.Y + selectRect.Height) return false;
            return true;
        }


        public static int GetMaxPage(int count, int pageSize)
        {
            return Math.Max(1, count / pageSize + (count % pageSize > 0 ? 1 : 0));
        }

        public static int Border(int value, int min, int max)
        {
            if (value < min) return min;
            if (value > max) return max;
            return value;
        }

        public static double Border(double value, double min, double max)
        {
            if (value < min) return min;
            if (value > max) return max;
            return value;
        }

        public static T SafeGet<T>(T[] arr, int index)
        {
            if (arr == null || index < 0 || index >= arr.Length)
            {
                return default;
            }
            return arr[index];
        }

        public static int ParseInt(string text)
        {
            if (IsEmpty(text))
            {
                return 0;
            }
            if (int.TryParse(text, out int result))
            {
                return result;
            }
            else
            {
                return 0;
            }
        }

        public static float ParseFloat(string text)
        {
            if (IsEmpty(text))
            {
                return 0f;
            }
            if (float.TryParse(text, out float result))
            {
                return result;
            }
            else
            {
                return 0;
            }
        }

        public static string FormatTime(int second)
        {
            TimeSpan ts = TimeSpan.FromSeconds(second);
            return string.Format("{0:D2}:{1:D2}:{2:D2}", ts.Hours, ts.Minutes, ts.Seconds);
        }

        public static string FormatTime(TimeSpan ts)
        {
            return string.Format("{0:D2}:{1:D2}:{2:D2}", ts.Hours, ts.Minutes, ts.Seconds);
        }

    }
}
